var COLS = 6;  //列数
var ROWS = 12; //行数
var colors = ['blue', 'yellow' ,'red', 'green'];  // 噗哟的颜色
var puyoGroup = [];
var board = []; // 数组信息（什么颜色的噗哟在哪里存在？）
var interval;  // 定时器ID，用来实现动画
var inputFlag = true;
var rensaCount = 0;  // 连锁数
var inputFlag = true; // 是否允许输入
var current;  //下降噗哟的形状信息
var currentX, currentY; //位置信息
var score = 0; //记录初始分数
var anotherX = 0;
var anotherY = 0;
var lose;
var rensaInterval;
var newX, newY;
var puyocolors = [];
var color_index =0;
var rensaCount = 0;


// 获取所有的Audio 元素, 加载所有的音频资源
// 定义所有的音频文件路径
var audioFiles = [
    "./asset/sound-effect.mp3",
    "./asset/sound-effect.mp3",
    "./asset/sound-effect.mp3"
  ];
  
// 创建一个数组来存储所有的Audio对象
var soundEffects = [];

//初始化音频
function initAudio() {
    // 循环遍历音频文件路径，创建对应的Audio对象，并将其存储到数组中
    for (var i = 0; i < audioFiles.length; i++) {
        var audio = new Audio(audioFiles[i]);
        soundEffects.push(audio);
    }
}

initAudio();

// 在砖块消失时播放不同音效的声音
function onBrickDisappear(ind) {
    soundEffects[ind].play();
}

function newShape() {
    var col = puyocolors[color_index];
    current = [[col[0],0],[col[1],0]];
    currentX = 2;
    currentY = 1;
    color_index  = ( color_index + 1 ) % puyocolors.length;
}
function createColors(){
    var cols = [64,64,64,64];

    for ( var y = 0; y < 128; ++y ) {
        puyocolors[ y ] = [0,0];
    }

    for (var x = 0; x < 256; x) {
        var cur = (Math.ceil(Math.random()*cols.length))%cols.length;
        if ( cols[cur] > 0 ) {
            cols[cur]--;
            puyocolors[x%128][Math.floor(x/128)]=colors[cur];
            x++;
        }
    }
}

function init() {
    for ( var y = 0; y < ROWS; ++y ) {
        board[ y ] = [];
        for ( var x = 0; x < COLS; ++x ) {
            board[ y ][ x ] = 0;
        }
    }
    createColors();
}

function tick() {
    if ( valid( 0, 1 ) ) {
        ++currentY;
        return
    }

    if(freeze()){
        return;
    }

    if(clear()){
        return;
    }

    if (lose) {
        newGame();
        return false;
    }    

    newShape();

}


//逆时针旋转
function rotate( current ) {
    newX =0;
    newY =0;
    if (current[0][0] != 0 ){
        if ( current[0][1] != 0 ){ 
            newX = - 1;          
	        if(currentY == 13 || board[currentY+1][currentX] != 0 ) {
		        newY--;
	        }
        }else if ( current[1][0] != 0){ 
            newY = 1;                   
	        if(currentX == 5){
		        newX--;
	        }else if(board[currentY+1][currentX+newX+1] != 0){
		        newY--;
	        }
        }
    }else if ( current[1][1] != 0 ){
        if ( current[0][1] != 0 ){  
            newY = -1;             
            if ( currentX == -1 ) {
            	newX++;
            	newY++;
            }
        }else if ( current[1][0] != 0){ 
            newX = 1;                     
        }
    }
    
    var newCurrent = [];    
    for ( var y = 0; y < 2; ++y ) {
        newCurrent[ y ] = [];
        for ( var x = 0; x < 2; ++x ) {
            newCurrent[ y ][ x ] = current[ 1 - x ][ y ];
        }
    }
    return newCurrent;
}

//顺时针旋转
function leftRotate( current ) {
    newX =0;
    newY =0;
    if (current[0][0] != 0 ){
        if ( current[0][1] != 0 ){    
            newY = -1;
        }else if ( current[1][0] != 0){        
            newX = -1;
            if ( board[ currentY + 1 ][ currentX - 1 ] != 0 ) {
            	newX++;
            }
        }
    }else if ( current[1][1] != 0 ){     
        if ( current[0][1] != 0 ){             
            newX = +1;
            if ( board[ currentY ][ currentX + 2 ] != 0 ) {
            	newX--;
            }

        }else if ( current[1][0] != 0){    
            newY = +1;
            if ( currentY == 12 || board[ currentY + 2 ][ currentX + 1 ] != 0 ) {
            	newY--;
            }
        }
    }
    
    var newCurrent = [[0,0],[0,0]];    
    for ( var y = 0; y < 2; ++y ) {
        for ( var x = 0; x < 2; ++x ) {
            newCurrent[1-y][x] = current[x][y];
        }
    }
    return newCurrent;
}
//暂停，重启
function pauseScreen(){
    if ( interval != 0 ){
        clearInterval( interval );
        interval = 0;
    }else {
        interval = setInterval( tick, 250 )
    }
}

function createPuyo(x, y, color){
    var puyo = {x: x , y: y, color: color};
    return puyo;
}

// 清除相同颜色的四个或以上的方块，并进行连锁处理，计分，移动方块等操作
function clear() {
    var is_erased;
    is_erased = false;
    for (var y = 0; y < ROWS; ++y ) {
        for (var x = 0; x < COLS; ++x ) {
            if (board[y][x] != 0) {
                // 判断该puyo是否可消除，可消除的话作上记录
                if (clearPuyo(x,y) ) {
                    is_erased = true;
                }
            }
        }
    }

    // 开始处理消除
    if (is_erased){ 
        if (interval != 0) {
            onBrickDisappear(0);
            // 停止计时器
            clearInterval(interval);
            
            interval = 0;
            // 禁止输入
            inputFlag = false;
            // 连锁用的计时器启动
            rensaInterval = setInterval(clear,500);
        }
        // todo 计分
        scorer();

        // todo 把数组中的非零元素（表示puyo对象）向下移动，直到遇到边界或者其他非零元素（表示puyo对象）
        packPuyos();

        // 连锁数
        rensaCount++;
        puyoGroup = [];
        return true;

    }

    // 连锁结束处理
    if (interval == 0) {
        clearInterval(rensaInterval);
        
        // todo 生成新的噗哟
        newShape();

        interval = setInterval(tick, 250);
        inputFlag = true;
        rensaCount = 0                
    }
    return false;
}

function createPuyo(x,y,col){
    var puyo = {x: x , y: y, col: col};
    return puyo;
}
// 清除指定位置的方块，如果该方块与相邻的同色方块形成四个或以上的组合，则一起清除，并返回true，否则返回false。
function clearPuyo(x,y) {
    var marked = [];     // 已搜素的位置
    for (var i = 0 ; i< ROWS; i++ ){
        marked[i] = [];
        for (var j = 0 ; j< COLS; j++ ){
            marked[i][j] = 0;
        }
    }

    // 如果不存在噗哟，什么也不做
    if(board[y][x] == 0) return false;

    // 指定要删除的噗哟的目标
    let puyo = createPuyo(x, y, board[y][x]);
    // 相同颜色的噗哟组
    var same_puyos = [puyo];

    // 寻找相同颜色的噗哟
    findPuyos(same_puyos, marked);

    // 噗哟有4个以上的情况
    if(same_puyos.length >= 4){
    	var pi = {size:same_puyos.length, color:same_puyos[0].color};
    	puyoGroup.push(pi);
        while(puyo = same_puyos.pop()){
            board[puyo.y][puyo.x] = 0;
        }
        return true
    }
    return false;
}


// 检查指定位置的方块是否满足条件condition，如果是，则判断是否与给定的颜色color相同，如果相同，则调用findPuyos函数，否则标记该位置为已访问
function checkPuyo(condition, x, y, color, same_puyos, marked){
    if(condition){
        if(board[y][x] == color ){
            same_puyos.push(createPuyo(x,y,color)); 
            findPuyos(same_puyos, marked);
        }else{
            marked[y][x] = true;
        }
    }
}

// 寻找与给定的方块同色且相邻的方块，并将它们加入到same_puyos数组中，同时标记已经访问过的位置。
function findPuyos(same_puyos, marked){
    // 以same_puyos中最后进入的噗哟为基准
    var puyo = same_puyos.pop()
    
    // 如果存在相同的puyo直接返回
    for(let i = 0; i < same_puyos.length; i++){
        if (same_puyos[i].x  == puyo.x
            && same_puyos[i].y == puyo.y
            && same_puyos[i].color == puyo.color){
            return;
        }
    }
    same_puyos.push(puyo);

    if(puyo.color == 0) {
        marked[puyo.y][puyo.x] = true;
        return;
    }

    // 如果已经搜索过了就什么都不做
    if(marked[puyo.y][puyo.x] == true) {
        return;
    }

    marked[puyo.y][puyo.x] = true;
    var x = puyo.x;
    var y = puyo.y;
    var col = puyo.col;

    // 检测左方噗哟
    checkPuyo(x > 0, x-1, y, col, same_puyos, marked);        
    // 检测右方噗哟
    checkPuyo(x < COLS-1, x+1, y, col, same_puyos, marked);        
    // 检测上方噗哟
    checkPuyo(y>1, x, y-1, col, same_puyos, marked);        
    // 检测下方噗哟
    checkPuyo(y<ROWS-1, x, y+1, col, same_puyos, marked);        
}

//左移、右移、软降
function keyPress( key ) {

    if (inputFlag == false) {
        return;
    }

    switch ( key ) {
    case 'left':
        if ( valid( -1 ) && puyoSize() > 1  ) {
            --currentX;
        }
        break;
    case 'right':
        if ( valid( 1 ) && puyoSize() > 1  ) {
            ++currentX;
        }
        break;
    case 'down':
        if ( valid( 0, 1 ) && puyoSize() > 1 ) {
            ++currentY;
        }
        break;
    case 'rotate':
        var rotated = rotate( current );
        //        f0001( rotated );
        if ( valid( newX, newY, rotated ) ) {
            current = rotated;
            currentX = currentX + newX
            currentY = currentY + newY
        }else if ( valid( newX + anotherX, newY + anotherY, rotated ) ) {
        	current = rotated;
            currentX = currentX + newX + anotherX
            currentY = currentY + newY + anotherY;
        }
        break;
    case 'leftRotate':
        var leftRotated = leftRotate( current );
        f0001( leftRotated );
        if ( valid( newX, newY, leftRotated ) ) {
            current = leftRotated
            currentX = currentX + newX
            currentY = currentY + newY;
        }else if ( valid( newX + anotherX, newY + anotherY, leftRotated ) ) {
        	current = leftRotated;
            currentX = currentX + newX + anotherX
            currentY = currentY + newY + anotherY;
        }
        break;
    case 'pauseScreen':
        pauseScreen();
        break;
    }
}

function valid( offsetX, offsetY, newCurrent ) {
    offsetX = offsetX || 0;
    offsetY = offsetY || 0;
    offsetX = currentX + offsetX;
    offsetY = currentY + offsetY;
    newCurrent = newCurrent || current;



    for ( var y = 0; y < 2; ++y ) {
        for ( var x = 0; x < 2; ++x ) {
            if ( newCurrent[ y ][ x ] ) {
                if ( typeof board[ y + offsetY ] == 'undefined'
                     || typeof board[ y + offsetY ][ x + offsetX ] == 'undefined'
                     || board[ y + offsetY ][ x + offsetX ]
                     || x + offsetX < 0
                     || y + offsetY >= ROWS
                     || x + offsetX >= COLS ) {
                    if (offsetY == 3 && offsetX == 2) lose = true;
                    if (offsetY == 2 && offsetX == 2) lose = true;
                    return false;
                }
            }
        }
    }
    return true;
}

//下落检测
function freeze() {              //下落检测
    for ( var y = 1; 0 <= y; --y ) {
        for ( var x = 0; x < 2; ++x ) {
            //底部附着或下方有气泡时
            if ( (y + currentY) >= (ROWS - 1)  ||        
                 board[ y + 1 +currentY][ x + currentX ] != 0){
                if ( current[ y ][ x ] ) {
                    board[ y + currentY ][ x + currentX ] = current[ y ][ x ];
                    current[y][x] = 0;
                }
            }
        }
    }

    // 检查是否还有剩余的气泡
    //如果没有，就直接返回false，不用等到循环结束
    // 如果有，就继续循环
    for ( var y = 1; 0 <= y; --y ) {
        for ( var x = 0; x < 2; ++x ) {
            if( current[y][x] ){
                return true;
            }
        }
    }
    
    return false;
    
}



function packPuyos(){
    for ( var x = 0; x < COLS; ++x ) {
        for ( var y = 0; y < ROWS-1; ++y ) {
            var starty = ROWS - y - 2
            //存在噗哟时
            if (board[starty][x] != 0){
                //搜索下几个噗哟
                var my = starty + 1
                for ( ; my < ROWS; my++) {
                    if ( board[my][x] != 0) break;
                }
                //如果噗哟不在下方，则移动
                if (my != starty + 1 &&  board[my-1][x] == 0) {
                    board[my-1][x]  = board[starty][x];
                    board[starty][x] = 0;
                }                
                
            }
        }
    } 
}


//重新开始游戏
function clearOPuyo( puyo ) {
	for ( var x = -1 ; x < 2; x++ ) {
		for ( var y = -1 ; y < 2; y++ ) {
			if ( Math.abs(x) != Math.abs(y) &&
			0 <= (puyo.y + y) &&
			(puyo.y + y) < board.length &&
			0 <= (puyo.x + x) &&
			(puyo.x + x) < board[0].length &&
			board[puyo.y + y][puyo.x + x] == 'gray' ) {
				board[puyo.y + y][puyo.x + x] = 0;
			}
		}
	}
}

//计分模块
function scorer() {
	var colorBonus = [ 0, 0, 3, 6, 12];
	var rensaBonus = [ 0, 8, 16, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 480, 512, 544];
	var connectBonus = [ 0, 0, 0, 0, 0, 2, 3, 4, 5, 6, 7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,];
	var currentBonus = 0;
	var erasedPuyos = 0;
	var uniquecolors = []
	for ( var  x = 0; x < puyoGroup.length; x++ ) {
		currentBonus = currentBonus + connectBonus[puyoGroup[x].size];
	}
	currentBonus = currentBonus + rensaBonus[rensaCount];
	for ( var  y = 0; y < puyoGroup.length; y++ ) {
		erasedPuyos = erasedPuyos + puyoGroup[y].size;
	}
	for ( var  z = 0; z < puyoGroup.length; z++ ) {
		var inserted = false;
		for ( var i = 0; i < uniquecolors.length; i++ ) {
			if ( uniquecolors[i] == puyoGroup[z].color ) {
				inserted = true;
				break;
			}
		}
		if ( inserted == false ) {
			uniquecolors.push(puyoGroup[z].color);
		}
	}
	currentBonus = currentBonus + connectBonus[uniquecolors.length];
	currentBonus = currentBonus || 1;
	score = score + currentBonus*10*erasedPuyos;
}

//创建新游戏
function newGame() {
    clearInterval(interval);
    init();
    newShape();
    lose = false;
    interval = setInterval( tick, 250 );
    score = 0;
}

newGame();

//计算puyo板的空间大小
function puyoSize() {
    var z = 0;
    for ( var y = 1; 0 <= y; --y ) {
        for ( var x = 0; x < 2; ++x ) {
            if ( current[ x ][ y ] != 0 ) {
                z++;
            }
        }
    }
    return z;
}   